#include "StdAfx.h"
#include "..\include\DefaultWorkQueue.h"
#include "..\include\LogManager.h"

using namespace Common;
//---------------------------------------------------------------------
DefaultWorkQueue::DefaultWorkQueue(const std::string& strWorkQueueName)
	: WorkQueue(strWorkQueueName)
{
}
//---------------------------------------------------------------------
DefaultWorkQueue::~DefaultWorkQueue()
{
	shutdown();
}
//---------------------------------------------------------------------
void DefaultWorkQueue::startup(bool forceRestart)
{
	if (m_bIsRunning)
	{
		if (forceRestart)
			shutdown();
		else
			return;
	}

	m_bShuttingDown = false;

	m_pWorkerFunc = new WorkerFunc(this);

	LogManager::getSingleton() <<
		"DefaultWorkQueue('" << m_strWorkQueueName<< "') initialising on thread " <<
		THREAD_CURRENT_ID
		<< ".";

	/*
	if (m_bWorkerRenderSystemAccess)
		Root::getSingleton().getRenderSystem()->preExtraThreadsStarted();
		*/
	m_NumThreadsRegisteredWithRS = 0;
	for( size_t threadId = 0; threadId < m_uWorkThreadCount; ++threadId )
	{
		THREAD_CREATE(pNewThread, *m_pWorkerFunc);
		m_Workers.push_back(pNewThread);
	}

	if (m_bWorkerRenderSystemAccess)
	{
		LOCK_MUTEX_NAMED(m_InitMutex, initLock)
		// have to wait until all threads are registered with the render system
		while( m_NumThreadsRegisteredWithRS < m_uWorkThreadCount )
			THREAD_WAIT(m_InitSync, m_InitMutex, initLock);

		//Root::getSingleton().getRenderSystem()->postExtraThreadsStarted();
	}

	m_bIsRunning = true;
}
//---------------------------------------------------------------------
void DefaultWorkQueue::notifyThreadRegistered()
{
	LOCK_MUTEX(m_InitMutex)

	++m_NumThreadsRegisteredWithRS;

	// wake up main thread
	THREAD_NOTIFY_ALL(m_InitSync);

}
//---------------------------------------------------------------------
void DefaultWorkQueue::shutdown()
{
	if( !m_bIsRunning )
		return;

	LogManager::getSingleton() <<
		"DefaultWorkQueue('" << m_strWorkQueueName << "') shutting down on thread " <<
		THREAD_CURRENT_ID
		<< ".";

	m_bShuttingDown = true;
	abortAllRequests();
	
	// wake all threads (they should check shutting down as first thing after wait)
	THREAD_NOTIFY_ALL(m_RequestCondition)

	// all our threads should have been woken now, so join
	for( WorkerThreadList::iterator itrPos = m_Workers.begin(); itrPos != m_Workers.end(); ++itrPos )
	{
		THREAD_TYPE* pWorkThread = (*itrPos);
		if( pWorkThread == NULL )
			continue;

		pWorkThread->join();
		
		delete pWorkThread;
	}
	m_Workers.clear();

	if( m_pWorkerFunc != NULL )
	{
		delete m_pWorkerFunc;
		m_pWorkerFunc = 0;
	}

	m_bIsRunning = false;
}
//---------------------------------------------------------------------
void DefaultWorkQueue::notifyWorkers()
{
	// wake up waiting thread
	THREAD_NOTIFY_ONE(m_RequestCondition)
}

//---------------------------------------------------------------------
void DefaultWorkQueue::waitForNextRequest()
{
	// Lock; note that THREAD_WAIT will free the lock
	LOCK_MUTEX_NAMED(m_mtxRequestMutex, queueLock);
	if( m_RequestQueue.empty() )
	{
		// frees lock and suspends the thread
		THREAD_WAIT(m_RequestCondition, mRequestMutex, queueLock);
	}
	// When we get back here, it's because we've been notified 
	// and thus the thread has been woken up. Lock has also been
	// re-acquired, but we won't use it. It's safe to try processing and fail
	// if another thread has got in first and grabbed the request

}
//---------------------------------------------------------------------
void DefaultWorkQueue::_threadMain()
{
	// default worker thread
	LogManager::getSingleton() << 
		"DefaultWorkQueue('" << getName() << "')::WorkerFunc - thread " 
		<< THREAD_CURRENT_ID << " starting.";

	// Initialise the thread for RS if necessary
	if( m_bWorkerRenderSystemAccess )
	{
		//Root::getSingleton().getRenderSystem()->registerThread();
		notifyThreadRegistered();
	}

	// Spin forever until we're told to shut down
	while( !isShuttingDown() )
	{
		waitForNextRequest();
		_processNextRequest();
	}

	LogManager::getSingleton() << 
		"DefaultWorkQueue('" << getName() << "')::WorkerFunc - thread " 
		<< THREAD_CURRENT_ID << " stopped.";

}
